#pragma once 
#include <iostream>
#include <queue>
#include <pthread.h>


template <class T>
class ThreadPool {
    public:
       ThreadPool(int num)
           :_num(num)
       {
           pthread_mutex_init(&lock, nullptr);
           pthread_cond_init(&cond, nullptr);
           InitThreadPool();
       } 
       
       void LockQueue() {
           pthread_mutex_lock(&lock);
       }

       void UnlockQueue() {
           pthread_mutex_unlock(&lock);
       }

       bool isEmpty() {
           return q.size() == 0;
       }

       void threadWait() {
           pthread_cond_wait(&cond, &lock);
       }

       void threadWakeUp() {
           pthread_cond_signal(&cond);
       }

       //void *Routinue(/*this  不用static修饰的话，会报错，因为类的成员函数默认有隐藏的this指针，而线程的例程只能传1个参数*/void *args) {
      static void *Routinue(void *args) {
           pthread_detach(pthread_self());
           ThreadPool *tp = (ThreadPool *)args;
           while (true) {
               tp->LockQueue();
               // 1、检测是否有任务
               while (tp->isEmpty()) {
                   // 任务队列为空，应该等待
                   tp->threadWait();
               }
               // 2、取任务
               T t;
               std::cout << t.sock << std::endl;
               tp->popTask(&t);
               // 3、处理任务
               tp->UnlockQueue();
               // 处理任务不需要在临界区处理
               std::cout << t.sock << std::endl;
               t();  //利用了Task类的仿函数 
           }
           return nullptr;
       }

       void InitThreadPool() {
           for (auto i = 0; i < _num; i++) {
               pthread_t tid;
               pthread_create(&tid, nullptr, Routinue, this);  // 把this指针传过去，方便在静态的例程中调用非静态的成员
           }
       }

       void PushTask(const T &in) {
           // 放任务
           LockQueue();
           q.push(in);
           threadWakeUp();
           UnlockQueue();
       }

       void popTask(T *out) {
          *out = q.front();
          q.pop();
       }
        
       ~ThreadPool()
        {
            pthread_mutex_destroy(&lock);
            pthread_cond_destroy(&cond);
        }
    private:
        int _num;  // 线程池中的线程数
        std::queue<T> q; // 给线程池派发任务的地点, 临界资源
        pthread_mutex_t lock;
        pthread_cond_t cond;
};

